package com.nineclock.attendance.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.nineclock.attendance.dto.AttendGroupDTO;
import com.nineclock.attendance.dto.AttendGroupPCExtraConfigDTO;
import com.nineclock.attendance.dto.AttendGroupPartDTO;
import com.nineclock.attendance.enums.AttendEnums;
import com.nineclock.attendance.mapper.AttendGroupMapper;
import com.nineclock.attendance.mapper.AttendGroupPartMapper;
import com.nineclock.attendance.pojo.AttendGroup;
import com.nineclock.attendance.pojo.AttendGroupPart;
import com.nineclock.attendance.service.AttendGroupService;
import com.nineclock.common.entity.PageResult;
import com.nineclock.common.enums.ResponseEnum;
import com.nineclock.common.exception.NcException;
import com.nineclock.common.threadlocal.CurrentUserHolder;
import com.nineclock.common.utils.BeanHelper;
import com.nineclock.system.feign.SysUserFeign;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author 黑马程序员
 * @Company http://www.ithiema.com
 * @Version 1.0
 */
@Service
@Slf4j
public class AttendGroupServiceImpl implements AttendGroupService {

    @Autowired
    AttendGroupMapper attendGroupMapper;

    @Autowired
    AttendGroupPartMapper attendGroupPartMapper;

    @Autowired
    SysUserFeign userFeign;

    /**
     * 分页查询考勤组列表
     * 1. 判断是否初次 登录（该企业没有管理员考勤组）
     * 2. 如果是初次登录，初始化默认考勤组（关联该企业所有的顶级部门）
     * 3. 对考勤组数据进行封装，并返回
     *
     *
     * @param page
     * @param pageSize
     * @return
     */
    @Override
    public PageResult<AttendGroupDTO> queryAttendGroupPage(Integer page, Integer pageSize) {
        //1. 判断是否初次 登录
        LambdaQueryWrapper<AttendGroup> attendGroupQw = new LambdaQueryWrapper<>();
        attendGroupQw.eq(AttendGroup::getCompanyId, CurrentUserHolder.get().getCompanyId());
        Integer count = attendGroupMapper.selectCount(attendGroupQw);
        if(count == 0){
            //如果count = 0 ，说明企业初次登录，初始化默认考勤组
            AttendGroup attendGroup = this.buildDefaultAttendGroup();
            attendGroupMapper.insert(attendGroup);

            //默认考勤组要与 所有的顶级部门关联
            List<Long> ids = userFeign.queryDepartmentIds().getData();
            if(CollectionUtil.isNotEmpty(ids)){
                for (Long id : ids) {
                    AttendGroupPart attendGroupPart = new AttendGroupPart();
                    attendGroupPart.setAttendGroupId(attendGroup.getId()); //考勤组id
                    attendGroupPart.setObjectType(AttendEnums.ATTEND_OBJECT_TYPE_DEP.value()); // 考勤关联的类型
                    attendGroupPart.setObjectId(id); // 部门或者是员工的id
                    attendGroupPart.setAttendType(AttendEnums.ATTEND_TYPE_YES.value()); //考勤的类型

                    attendGroupPartMapper.insert(attendGroupPart);
                }
            }

        }

        //分页查询考勤组
        Page<AttendGroup> attendGroupPage = new Page<>(page, pageSize);

        attendGroupPage = attendGroupMapper.selectPage(attendGroupPage, attendGroupQw);
        //获取考勤组列表数据
        List<AttendGroup> attendGroupList = attendGroupPage.getRecords();
        List<AttendGroupDTO> attendGroupDTOList = BeanHelper.copyWithCollection(attendGroupList, AttendGroupDTO.class);
        //为每个考勤组查询 关联的人数
        for (AttendGroupDTO attendGroupDTO : attendGroupDTOList) {
            //查询该该考勤组 对应的部门
            LambdaQueryWrapper<AttendGroupPart> attendGroupPartQw = new LambdaQueryWrapper<>();
            attendGroupPartQw.eq(AttendGroupPart::getAttendGroupId, attendGroupDTO.getId());
            //根据考勤组id 查询对应的 部门或者是员工  的关联关联
            List<AttendGroupPart> attendGroupPartList = attendGroupPartMapper.selectList(attendGroupPartQw);

            //部门id集合
            List<Long> departmentIds = new ArrayList<>();
            //员工id集合
            List<Long> userIds = new ArrayList<>();

            //统计 部门和员工的 id
            if(CollectionUtil.isNotEmpty(attendGroupPartList)){
                for (AttendGroupPart attendGroupPart : attendGroupPartList) {
                    //如果是部门
                    if( attendGroupPart.getObjectType() == AttendEnums.ATTEND_OBJECT_TYPE_DEP.value()){
                        departmentIds.add(attendGroupPart.getObjectId());
                    }
                    if( attendGroupPart.getObjectType() == AttendEnums.ATTEND_OBJECT_TYPE_USER.value()){
                        userIds.add(attendGroupPart.getObjectId());
                    }

                }
            }

            //查询该该考勤组 对应的部门  相关联的人数
            Integer departmentUserCount = userFeign.queryUserCountByDepartmentId(departmentIds).getData();

            attendGroupDTO.setMemberNum((departmentUserCount == null ? 0: departmentUserCount) + userIds.size());
        }
        //封装返回值
        return new PageResult(attendGroupPage.getTotal(), attendGroupPage.getPages(), attendGroupDTOList);
    }

    /**
     * 1. 新增考勤组
     * 2. 维护考勤组与 部门和员工的关系(删除原有的关系，添加新的关系)
     * @param attendGroupDTO
     */
    @Override
    public void addAttendGroup(AttendGroupDTO attendGroupDTO) {
        if(attendGroupDTO == null){
            throw new NcException(ResponseEnum.INVALID_PARAM_ERROR);
        }
        AttendGroup attendGroup = BeanHelper.copyProperties(attendGroupDTO, AttendGroup.class);
        attendGroup.setCompanyId(CurrentUserHolder.get().getCompanyId());
        //设置工作日
        attendGroup.setWorkdays(StrUtil.join(",", attendGroupDTO.getWorkdays().toArray()));
        attendGroup.setCreateUserId(CurrentUserHolder.get().getCompanyUserId());

        //获取需要和无需打开的日期集合
        List<AttendGroupPCExtraConfigDTO> extraConfig = attendGroupDTO.getExtraConfig();
        //必须打卡的日期
        List<String> necessaryDateList = extraConfig.stream().filter(attendGroupPCExtraConfigDTO -> {
            return attendGroupPCExtraConfigDTO.getRequiredAttend() == 1;
        }).map(attendGroupPCExtraConfigDTO -> {
            return attendGroupPCExtraConfigDTO.getSetDate();
        }).collect(Collectors.toList());

        //设置必须打卡的日期
        attendGroup.setNecessaryTimeList(StrUtil.join(",", necessaryDateList));
        //无需打卡的日志
        List<String> unnecessaryDateList = extraConfig.stream().filter(attendGroupPCExtraConfigDTO -> {
            return attendGroupPCExtraConfigDTO.getRequiredAttend() == 0;
        }).map(attendGroupPCExtraConfigDTO -> {
            return attendGroupPCExtraConfigDTO.getSetDate();
        }).collect(Collectors.toList());
        //设置无需打卡的日期
        attendGroup.setUnnecessaryTimeList(StrUtil.join(",", unnecessaryDateList));

        attendGroup.setCreateTime(new Date());
        //保存考勤组信息
        attendGroupMapper.insert(attendGroup);


        //维护关系
        this.setAttendGroupPart(attendGroupDTO ,attendGroup);
    }

    @Override
    public AttendGroupDTO getAttendGroupByUserId() {
        //获取员工id
        Long companyUserId = CurrentUserHolder.get().getCompanyUserId();
        //获取该员工 与 考勤组的关系对象
        LambdaQueryWrapper<AttendGroupPart> attendGroupPartQw = new LambdaQueryWrapper<>();
        attendGroupPartQw.eq(AttendGroupPart::getObjectId, companyUserId);
        attendGroupPartQw.eq(AttendGroupPart::getObjectType, AttendEnums.ATTEND_OBJECT_TYPE_USER.value());
        //获取 关系对象
        AttendGroupPart attendGroupPart = attendGroupPartMapper.selectOne(attendGroupPartQw);
        //没有找到员工的考勤组的关系， 此时需要找该用户所在的部门的id， 依次查找所关联的考勤组
        if(attendGroupPart == null){
            //员工所在的部门的id集合
            List<Long> ids = userFeign.queryDepartmentsByUserId(companyUserId).getData();
            if(CollectionUtil.isNotEmpty(ids)){
                for (Long departmentId : ids) {
                    LambdaQueryWrapper<AttendGroupPart> wrapper = new LambdaQueryWrapper<>();
                    wrapper.eq(AttendGroupPart::getObjectId, departmentId);
                    wrapper.eq(AttendGroupPart::getObjectType, AttendEnums.ATTEND_OBJECT_TYPE_DEP.value());

                    attendGroupPart = attendGroupPartMapper.selectOne(wrapper);
                    if(attendGroupPart != null){
                        break;
                    }
                }
            }
        }



        Long attendGroupId = attendGroupPart.getAttendGroupId();
        AttendGroup attendGroup = attendGroupMapper.selectById(attendGroupId);
        AttendGroupDTO attendGroupDTO = BeanHelper.copyProperties(attendGroup, AttendGroupDTO.class);

        attendGroupDTO.setWorkdays(Arrays.asList(attendGroup.getWorkdays().split(",")));

        return attendGroupDTO;

    }

    private void setAttendGroupPart(AttendGroupDTO attendGroupDTO, AttendGroup attendGroup) {

        //参与考勤的人员
        List<AttendGroupPartDTO> participates = attendGroupDTO.getParticipates();

        if(CollectionUtil.isNotEmpty(participates)){
            for (AttendGroupPartDTO participate : participates) {

                //先删除部门/用户 与 原来考勤组的关系
                LambdaQueryWrapper<AttendGroupPart> attendGroupPartQw = new LambdaQueryWrapper<>();
                attendGroupPartQw.eq(AttendGroupPart::getObjectId, participate.getObjectId()); //条件：部门/员工id
                attendGroupPartQw.eq(AttendGroupPart::getObjectType, participate.getObjectType()); //条件： 部门/员工(类型)
                attendGroupPartMapper.delete(attendGroupPartQw);

                AttendGroupPart attendGroupPart = new AttendGroupPart();
                attendGroupPart.setAttendGroupId(attendGroup.getId());
                attendGroupPart.setObjectType(participate.getObjectType());
                attendGroupPart.setObjectId(participate.getObjectId());
                attendGroupPart.setAttendType(1);

                attendGroupPartMapper.insert(attendGroupPart);
            }
        }



        //不参加考勤的人员
        List<AttendGroupPartDTO> notParticipates = attendGroupDTO.getNotParticipates();

        if(CollectionUtil.isNotEmpty(notParticipates)){
            for (AttendGroupPartDTO participate : notParticipates) {

                //先删除部门/用户 与 原来考勤组的关系
                LambdaQueryWrapper<AttendGroupPart> attendGroupPartQw = new LambdaQueryWrapper<>();
                attendGroupPartQw.eq(AttendGroupPart::getObjectId, participate.getObjectId()); //条件：部门/员工id
                attendGroupPartQw.eq(AttendGroupPart::getObjectType, participate.getObjectType()); //条件： 部门/员工(类型)
                attendGroupPartMapper.delete(attendGroupPartQw);

                AttendGroupPart attendGroupPart = new AttendGroupPart();
                attendGroupPart.setAttendGroupId(attendGroup.getId());
                attendGroupPart.setObjectType(participate.getObjectType());
                attendGroupPart.setObjectId(participate.getObjectId());
                attendGroupPart.setAttendType(2);

                attendGroupPartMapper.insert(attendGroupPart);
            }
        }
    }

    private AttendGroup buildDefaultAttendGroup() {
        AttendGroup attendGroup = new AttendGroup();
        attendGroup.setName("默认考勤组");
        attendGroup.setCompanyId(CurrentUserHolder.get().getCompanyId());
        attendGroup.setStartWorkTime("09:00:00");
        attendGroup.setAllowLateMinutes(10);
        attendGroup.setLateMinutes(30);
        attendGroup.setStartNoonRestTime("12:00:00");
        attendGroup.setEndNoonRestTime("14:00:00");
        attendGroup.setOffWorkTime("17:00:00");
        attendGroup.setWorkdays("1,1,1,1,1,0,0");
        attendGroup.setAddressName("北京市昌平区北七家TBD云集中心");
        attendGroup.setLat(116.373778);
        attendGroup.setLng(40.104674);
        attendGroup.setAddressRange(3000);
        attendGroup.setCreateUserId(CurrentUserHolder.get().getCompanyUserId());
        attendGroup.setCreateTime(new Date());
        return attendGroup;
    }
}
